package org.game.module.datingbo.trigger;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiaoleilu.hutool.date.DateUnit;
import com.xiaoleilu.hutool.date.DateUtil;
import org.cfg.DatingRuleCfg;
import org.cfg.cache.DatingRuleCfgCache;
import org.cfg.cache.DiscreteDataCfgCache;
import org.constant.DatingConstant;
import org.constant.DiscreteDataID;
import org.constant.DiscreteDataKey;
import org.constant.RoleConstant;
import org.game.constant.CityConstant;
import org.game.constant.DatingTypeConstant;
import org.game.db.bean.*;
import org.game.db.cache.CityCache;
import org.game.db.cache.RoleCache;
import org.game.db.proxy.bean.CityDatingRecordProxy;
import org.game.module.datingbo.DatingBO;
import org.game.module.datingbo.DatingType;
import org.game.msgBuilder.DatingMsgBuilder;
import org.utils.TimeUtil;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 约定约会触发器
 * Created by fxf on 2018-3-14.
 */
@DatingType(DatingTypeConstant.DATING_TYPE_RESERVE)
public class ReserveDatingTrigger extends AbstractCityDatingTrigger {


    @Override
    public void triggerDating(Player player, Map<String, List<Integer>> timeFrame, Date now) {
        List<Integer> triggerTimeFrame = timeFrame.get(DatingConstant.TRIGGER_TIME);
        if (alreadyTrigger(player, triggerTimeFrame)) {
            return;
        }
        List<Integer> freeCityList = CityCache.me().getCityCacheProxy().getFreeCityList(player, city -> city.getCityProxy().getCfg().getBuildType() == CityConstant.WORK_ZONE || city.getCityProxy().getCfg().getBuildType() == CityConstant.NOT_WORK_ZONE);
        if (freeCityList.size() == 0) {
            return;
        }
        List<Integer> freeRoleList = getFreeRole(player);
        if (freeRoleList.size() == 0) {
            return;
        }
        Collections.shuffle(freeRoleList);
        List<DatingRuleCfg> usableDatingCfgList = getUsableReserveDatingRuleCfg(freeRoleList, freeCityList);
        filtrateDating(player, usableDatingCfgList, timeFrame,now);
    }

    @Override
    public void refreshCityDating(Player player, List<CityDatingRecord> recordList, Date now) {
        List<CityDatingRecord> updateList = Lists.newArrayList();
        List<CityDatingRecord> outTimeRecordList = Lists.newArrayList();
        for (CityDatingRecord record : recordList) {
            if (datingTimeUpdate(record, now)) {
                updateList.add(record);
                //状态为无约会说明记录已经过期
                if (record.getCityDatingRecordProxy().getState() == DatingConstant.RESERVE_DATING_STATE_NO_DATING) {
                    record.delete();
                    outTimeRecordList.add(record);
                }
            }
        }
        if (updateList.size() > 0) {
            player.getPlayerProxy().sendMsg(DatingBO.updateCityDatingList, DatingMsgBuilder.buildCityDatingInfoList(updateList));
        }
        refreshCity(player, outTimeRecordList);
    }

    private List<Integer> getFreeRole(Player player) {
        List<Role> all = RoleCache.me().getByPlayerId(player.getId());
        return all.stream()
                .filter(role -> !role.getRoleProxy().isCriticalPoint())
                .filter(role -> getReserveDateRecord(role) == null)
                .filter(role -> role.getWorkBuildingId() == 0)//非打工状态
                .filter(role -> role.getMood() > DiscreteDataCfgCache.me().getIntData(DiscreteDataID.DATING, DiscreteDataKey.MOOD))//心情值符合条件
                .map(role -> role.getCid())
                .collect(Collectors.toList());
    }

    private List<DatingRuleCfg> getUsableReserveDatingRuleCfg(List<Integer> roleCidList, List<Integer> cityCidList) {
        List<DatingRuleCfg> all = DatingRuleCfgCache.me().getAll();
        return all.stream()
                .filter(cfg -> cfg.getType() == DatingTypeConstant.DATING_TYPE_RESERVE)
                .filter(cfg -> cityCidList.contains(cfg.getEnterCondtionByType(DatingConstant.ENTER_CDTION_KEY_CITY_CID)))
                .filter(cfg -> cfg.getEnterCondition().get(DatingConstant.ENTER_CDTION_KEY_ROLE_CIDS) != null)
                .filter(cfg -> roleCidList.containsAll((Collection<?>) cfg.getEnterCondition().get(DatingConstant.ENTER_CDTION_KEY_ROLE_CIDS)))
                .collect(Collectors.toList());
    }


    @Override
    int getTriggerRate(Role role, DatingRuleCfg datingRuleCfg) {
        int mood = role.getMood();
        if (mood <= DiscreteDataCfgCache.me().getIntData(DiscreteDataID.DATING, DiscreteDataKey.MOOD))
            return 0;
        int percent = (mood - 60) * 10 / 100 + 10 + role.getRoleProxy().getEffectByType(RoleConstant.EFFECT_TYPE_3);
        return percent * getDampingRate(role) / 100;
    }

    /**
     * 创建城市约会记录
     *
     * @param player
     * @param datingRuleCfg
     */
    @Override
    CityDatingRecord createCityDatingRecord(Player player, DatingRuleCfg datingRuleCfg, Map<String, List<Integer>> timeFrame,Date now) {
        CityDatingRecord record = new CityDatingRecord(0l, player.getId(), datingRuleCfg.getId(), datingRuleCfg.getEnterCondtionByType(DatingConstant.ENTER_CDTION_KEY_CITY_CID), datingRuleCfg.getType(), Maps.newHashMap());
        record.getCityDatingRecordProxy().setTriggerTime(now);
        record.getCityDatingRecordProxy().setState(DatingConstant.RESERVE_DATING_STATE_HAVE_INVITATION);
        record.getCityDatingRecordProxy().setDatingTimeFrame(timeFrame.get(DatingConstant.DATING_TIME));
        Calendar datingTime = Calendar.getInstance();
        datingTime.set(Calendar.SECOND, 0);
        datingTime.set(Calendar.MILLISECOND, 0);

        datingTime.set(Calendar.HOUR_OF_DAY, record.getCityDatingRecordProxy().getDatingTimeFrame().get(0));
        datingTime.set(Calendar.MINUTE, record.getCityDatingRecordProxy().getDatingTimeFrame().get(1));
        record.getCityDatingRecordProxy().setDatingBeginTime(datingTime.getTimeInMillis());

        datingTime.set(Calendar.HOUR_OF_DAY, record.getCityDatingRecordProxy().getDatingTimeFrame().get(2));
        datingTime.set(Calendar.MINUTE, record.getCityDatingRecordProxy().getDatingTimeFrame().get(3));
        record.getCityDatingRecordProxy().setDatingEndTime(datingTime.getTimeInMillis());

        record.insert();
        return record;
    }


    /**
     * 更新约会状态
     */
    public boolean datingTimeUpdate(CityDatingRecord record, Date date) {
        Calendar beginTime = Calendar.getInstance();
        beginTime.setTimeInMillis(record.getCityDatingRecordProxy().getDatingBeginTime());
        Calendar endTime = Calendar.getInstance();
        endTime.setTimeInMillis(record.getCityDatingRecordProxy().getDatingEndTime());
        CityDatingRecordProxy recordProxy = record.getCityDatingRecordProxy();

        boolean update = false;
        if (isBeginningDating(date, beginTime, endTime, recordProxy)) {
            //约会时间开始
            recordProxy.setState(DatingConstant.RESERVE_DATING_STATE_DATING_TIME_START);
            record.update();
            update = true;
        } else if (isLateDating(date, endTime, recordProxy)) {
            //约会时间已过
            recordProxy.setState(DatingConstant.RESERVE_DATING_STATE_DATING_TIME_END);
            record.update();
            update = true;
        } else if (recordProxy.getState() == DatingConstant.RESERVE_DATING_STATE_HAVE_INVITATION) {
            int outDatingTime = ((Map<Integer, Integer>) DiscreteDataCfgCache.me().getData(DiscreteDataID.DATING, DiscreteDataKey.DATING_OUT_TIME)).get(DatingTypeConstant.DATING_TYPE_RESERVE);
            //未接受邀请且超时 删除
            if (DateUtil.between(record.getCreateDate(), date, DateUnit.MINUTE) >= outDatingTime) {
                record.delete();
                recordProxy.setState(DatingConstant.RESERVE_DATING_STATE_NO_DATING);
                update = true;
            }
        } else if (!TimeUtil.isSameDay(record.getCreateDate().getTime(), date.getTime())) {
            //跨天
            //1.非正在约会状态则删除 2.上线的时候会将长在isRunning改为false，所以不用再考虑上线的情况
            record.delete();
            recordProxy.setState(DatingConstant.RESERVE_DATING_STATE_NO_DATING);
            update = true;
        }
        return update;
    }

    private boolean isLateDating(Date date, Calendar endTime, CityDatingRecordProxy recordProxy) {
        return (recordProxy.getState() == DatingConstant.RESERVE_DATING_STATE_DATING_TIME_START
                || recordProxy.getState() == DatingConstant.RESERVE_DATING_STATE_ACCEPT_INVITATION)
                && endTime.getTimeInMillis() <= date.getTime();
    }

    private boolean isBeginningDating(Date date, Calendar beginTime, Calendar endTime, CityDatingRecordProxy recordProxy) {
        return recordProxy.getState() == DatingConstant.RESERVE_DATING_STATE_ACCEPT_INVITATION
                && beginTime.getTimeInMillis() <= date.getTime()
                && endTime.getTimeInMillis() >= date.getTime();
    }
}


